/*
 * Copyright (c) 2020-2022 Jinsp-tech. All rights reserved.
 */

package com.jinsp.networklibrary.filter;

import android.util.Log;

import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.reflect.TypeToken;
import com.jinsp.networklibrary.bean.TCPBaseDataBean;
import com.jinsp.networklibrary.command.CommandManager;
import com.jinsp.networklibrary.command.ITCPCommand;
import com.jinsp.networklibrary.command.TCPBaseDataBeanFactory;
import com.jinsp.networklibrary.command.TCPCommandData;
import com.jinsp.networklibrary.command.TCPCommandFactory;

import org.apache.mina.core.filterchain.IoFilterAdapter;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.core.write.WriteRequest;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by luoshuai on 1/13/22
 * <p>
 * 对象数据转换为Json过滤器
 */
public class JsonFilter extends IoFilterAdapter {

    private final String TAG = "JsonFilter";
    private final Gson gson;
    private final int clientStateData;
    private final boolean isSendDataForJsonString;      //发送的数据是否为Json字符串
    private final Type tcpBaseDataBeanJsonArrayType;
    private final Type tcpBaseDataBeanJsonObjectType;
    private final Type tcpBaseDataBeanJsonStringType;
    private final Type jsonArrayType, jsonObjectType;

    public JsonFilter(int clientStateData, boolean isSendDataForJsonString) {
        this.clientStateData = clientStateData;
        this.isSendDataForJsonString = isSendDataForJsonString;
        gson = new Gson();
        TypeToken<TCPBaseDataBean<JsonArray>> tcpBaseDataBeanJsonArrayTypeToken = new TypeToken<TCPBaseDataBean<JsonArray>>() {
        };
        TypeToken<TCPBaseDataBean<JsonObject>> tcpBaseDataBeanJsonObjectTypeToken = new TypeToken<TCPBaseDataBean<JsonObject>>() {
        };
        TypeToken<TCPBaseDataBean<String>> jsonStringTypeToken = new TypeToken<TCPBaseDataBean<String>>() {
        };
        TypeToken<JsonArray> jsonArrayTypeToken = new TypeToken<JsonArray>() {
        };
        TypeToken<JsonObject> jsonObjectTypeToken = new TypeToken<JsonObject>() {
        };
        tcpBaseDataBeanJsonArrayType = tcpBaseDataBeanJsonArrayTypeToken.getType();
        tcpBaseDataBeanJsonObjectType = tcpBaseDataBeanJsonObjectTypeToken.getType();
        tcpBaseDataBeanJsonStringType = jsonStringTypeToken.getType();
        jsonArrayType = jsonArrayTypeToken.getType();
        jsonObjectType = jsonObjectTypeToken.getType();
    }

    @Override
    public void filterWrite(NextFilter nextFilter, IoSession session, WriteRequest writeRequest) throws Exception {
        //数据转换为json字符串
        Object originalMessage = writeRequest.getOriginalMessage();
        String sendData = originalMessage.toString();
        Log.d(TAG, "客户端原始数据：" + sendData);
        if (originalMessage instanceof ITCPCommand) {
            ITCPCommand<?, ?> command = (ITCPCommand<?, ?>) originalMessage;
            int commandNumber = command.getCommandNumber();
            Object commandData = command.getCommandData();
            if (isSendDataForJsonString) {
                //发送数据为Json字符串数据
                commandData = gson.toJson(commandData);
            }
            //构建TCPBaseDataBean
            TCPBaseDataBean<Object> tcpBaseDataBean = TCPBaseDataBeanFactory.getTCPBaseDataBean(commandNumber);
            tcpBaseDataBean.setState(clientStateData);
            tcpBaseDataBean.setData(commandData);
            sendData = gson.toJson(tcpBaseDataBean);
        } else if (originalMessage instanceof TCPBaseDataBean) {
            sendData = gson.toJson(originalMessage);
        }
        Log.d(TAG, "客户端发送数据：" + sendData);
        writeRequest.setMessage(sendData);
        super.filterWrite(nextFilter, session, writeRequest);
    }

    @Override
    public void messageReceived(NextFilter nextFilter, IoSession session, Object message) throws Exception {
        Log.d(TAG, "客户端收到回应数据：" + message);
        if (message instanceof String) {
            String jsonData = (String) message;
            TCPBaseDataBean<?> tcpBaseDataBean = null;
            boolean isJsonString = false;
            //查看是否为Json数组
            try {
                tcpBaseDataBean = gson.fromJson(jsonData, tcpBaseDataBeanJsonArrayType);
                Log.d(TAG, "客户端收到数据是JSON数组");
            } catch (Exception e) {
                Log.e(TAG, "客户端收到数据不是Json数组");
                //查看是否为Json对象
                try {
                    tcpBaseDataBean = gson.fromJson(jsonData, tcpBaseDataBeanJsonObjectType);
                    Log.d(TAG, "客户端收到数据是JSON对象");
                } catch (Exception e1) {
                    Log.e(TAG, "客户端收到数据不是JSON对象");
                    //查看是否为Json字符串
                    try {
                        tcpBaseDataBean = gson.fromJson(jsonData, tcpBaseDataBeanJsonStringType);
                        isJsonString = true;
                        Log.d(TAG, "客户端收到数据是JSON字符串");
                    } catch (Exception e3) {
                        Log.e(TAG, "未找到合适Json解析类型");
                    }
                }
            }
            //解析为TCPBaseDataBean数据
            if (tcpBaseDataBean != null) {
                ITCPCommand<?, ?> handleTCPReceiveDataCommand = CommandManager.getInstance().getCommand(tcpBaseDataBean.getCommandNumber());
                if (handleTCPReceiveDataCommand != null) {
                    Object data = tcpBaseDataBean.getData();
                    Object realData = null;
                    if (!isJsonString) {
                        //获取该命令的泛型并解析最终数据
                        realData = tryParseJson(handleTCPReceiveDataCommand, data);
                    } else {
                        //解析Json字符串
                        Object jsonStringParse = null;
                        String sJsonStringData = data.toString();
                        try {
                            jsonStringParse = gson.fromJson(data.toString(), jsonArrayType);
                            Log.d(TAG, "客户端收到Json字符串数据解析是为Json数组");
                        } catch (Exception e) {
                            Log.e(TAG, "客户端收到Json字符串数据解析不是为Json数组");
                            try {
                                jsonStringParse = gson.fromJson(sJsonStringData, jsonObjectType);
                                Log.d(TAG, "客户端收到Json字符串数据解析是为Json对象");
                            } catch (Exception e1) {
                                Log.e(TAG, "客户端收到Json字符串数据解析不是为Json对象");
                            }
                        }
                        if (jsonStringParse != null) {
                            realData = tryParseJson(handleTCPReceiveDataCommand, jsonStringParse);
                        }
                    }
                    if (realData != null) {
                        //获取命令对象，享元模式
                        TCPCommandData tcpCommandData = TCPCommandFactory.getTCPCommand(tcpBaseDataBean.getCommandNumber());
                        tcpCommandData.setData(realData);
                        tcpCommandData.setState(tcpBaseDataBean.getState());
                        super.messageReceived(nextFilter, session, tcpCommandData);
                        return;
                    }
                }
            }
        }
        super.messageReceived(nextFilter, session, message);
    }

    /**
     * 解析Json数据为命令数据
     *
     * @param handleTCPReceiveDataCommand 指定命令
     * @param data                        原始Json数据
     * @return 解析后的Json实体类数据
     */
    private Object tryParseJson(ITCPCommand<?, ?> handleTCPReceiveDataCommand, Object data) {
        //获取该命令的泛型并解析最终数据
        Type[] genericInterfaces = handleTCPReceiveDataCommand.getClass().getGenericInterfaces();
        if (genericInterfaces != null && genericInterfaces.length > 0) {
            Type type = genericInterfaces[0];
            if (type instanceof ParameterizedType) {
                ParameterizedType parameterizedType = (ParameterizedType) type;
                //获取泛型类型
                Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
                if (actualTypeArguments != null && actualTypeArguments.length > 1) {
                    //获取接收端数据类型
                    Type actualTypeArgument = actualTypeArguments[1];
                    Log.d(TAG, "获取到接收数据泛型为: " + actualTypeArgument);
                    //解析json数据为该类型
                    if (data instanceof JsonArray) {
                        //json数组转集合对象
                        JsonArray jsonArray = (JsonArray) data;
                        List<Object> list = new ArrayList<>(jsonArray.size());
                        for (JsonElement element : jsonArray) {
                            Object everyDataBean = gson.fromJson(element, actualTypeArgument);
                            list.add(everyDataBean);
                        }
                        return list;
                    } else if (data instanceof JsonObject) {
                        //json对象转换
                        return gson.fromJson(data.toString(), actualTypeArgument);
                    }
                }
            }
        }
        return data;
    }
}
